import { useRef } from "react";
import { useEffect, useState } from "react";
import LazyImage from "./lazyImage";

const Waterfall = ({ maxColumnsNum = 6, imgArr = [] }: {
    maxColumnsNum: number,
    imgArr: string[]
}) => {
    const [dataSource, setDataSource] = useState<any[][]>([]);
    const columnsLengthArr = useRef<number[]>([]);
    const latestDataSource = useRef<typeof dataSource>([]);
    const currentColumnsNum = useRef<number>();
    const renderedCount = useRef<number>(0);
    const currentContainerWidth = useRef();
    const containerRef = useRef<any>(null);
    function updateData(newData: typeof dataSource) {
        latestDataSource.current = [...newData];
        renderedCount.current++;
        setDataSource(newData);
    }
    function initImg(currentIndex = 0, reRender = false) {
        const columnsNum = currentColumnsNum.current;
        if (currentIndex === 0) {
            columnsLengthArr.current = new Array(columnsNum).fill(0);
            renderedCount.current = 0;
            latestDataSource.current.length = 0;
        }
        if (currentIndex === imgArr.length) return;
        if (latestDataSource.current.length === 0) {
            const newData = new Array(columnsNum).fill(0).map(() => [] as string[]);
            newData[0].push(imgArr[currentIndex]);
            updateData(newData);
        } else {
            const newData = [...latestDataSource.current];
            let minLengthIndex = 0;
            for (let i = 0; i < newData.length; i++) {
                if (newData[i].length === 0) {
                    newData[i].push(imgArr[currentIndex]);
                    updateData(newData);
                    return;
                }
                minLengthIndex =
                    columnsLengthArr.current[minLengthIndex] > columnsLengthArr.current[i]
                        ? i
                        : minLengthIndex;
            }
            newData[minLengthIndex].push(imgArr[currentIndex]);
            updateData(newData);
        }
        if (reRender)
            requestAnimationFrame(() => {
                initImg(renderedCount.current);
            });
    }
    function updateColumnsHeight(
        e: React.SyntheticEvent<HTMLImageElement, Event>,
        index: number
    ) {
        columnsLengthArr.current[index] += e.currentTarget.clientHeight;
        requestAnimationFrame(() => {
            initImg(renderedCount.current);
        });
    }
    function calculateColumns() {
        if (!containerRef.current) return;
        const containerWidth = containerRef.current.clientWidth;
        if (currentContainerWidth.current === containerWidth) return false;
        currentContainerWidth.current = containerWidth;
        if (containerWidth < 600) {
            if (currentColumnsNum.current === 2) return false;
            currentColumnsNum.current = 2;
        } else if (containerWidth < 900) {
            if (currentColumnsNum.current === 3) return false;
            currentColumnsNum.current = 3;
        } else {
            if (currentColumnsNum.current === maxColumnsNum) return false;
            currentColumnsNum.current = maxColumnsNum;
        }
        return true
    }
    useEffect(() => {
        const handleResize = () => {
            if (calculateColumns()) initImg(0, true);
        };
        window.addEventListener("resize", handleResize);
        return () => window.removeEventListener("resize", handleResize);
    }, []);
    useEffect(() => {
        calculateColumns();
        initImg(0, true);
    }, [imgArr]);
    return (
        <div style={{ width: "100%", overflow: "auto" }}>
            <div style={{ display: "flex", columnGap: 5 }} ref={containerRef}>
                {dataSource.map((item, index) => {
                    return (
                        <div key={index} style={{ flex: 1 }}>
                            {item.map((_item) => (
                                <LazyImage
                                    onLoad={(e) => updateColumnsHeight(e, index)}
                                    src={_item}
                                    alt=""
                                    style={{ width: "100%", maxHeight: 300, objectFit: "cover" }}
                                />
                            ))}
                        </div>
                    );
                })}
            </div>
        </div>
    );
};
export default Waterfall;